package com.cyf.restTemplate.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.util.List;

/**
 * @author chenyifan
 * @create 2025-04-07 10:05
 */
@Configuration
public class RestTemplateConfig {


    @Bean("httpClient")
    public HttpClient httpClient () {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();

        try {
            // 信任所有证书
            SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial(new TrustAllStrategy()).build();
            // 关闭了主机名验证，接受任何有效的SSL会话并匹配目标主机
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("https", new SSLConnectionSocketFactory(sslContext, hostnameVerifier))
                    .register("http", new PlainConnectionSocketFactory())
                    .build();

            // 自定义的连接池管理器
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            connectionManager.setMaxTotal(200);  // 最大连接数
            connectionManager.setDefaultMaxPerRoute(50);  // 每个路由默认连接数

            httpClientBuilder
                    .setConnectionManager(connectionManager)
                    .setSSLContext(sslContext)
                    .setSSLHostnameVerifier(hostnameVerifier);

        } catch (Exception e) {
            throw new RuntimeException("Failed to create HTTP client", e);
        }
        return httpClientBuilder.build();
    }


    @Bean("clientHttpRequestFactory")
    public ClientHttpRequestFactory clientHttpRequestFactory(@Qualifier("httpClient") HttpClient httpClient) {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        // 建立连接的超时时间（单位/毫秒），默认值： -1，为无限超时
        clientHttpRequestFactory.setConnectTimeout(10 * 1000);
        // 等数据的超时时间（单位/毫秒），默认值： -1，为无限超时
        clientHttpRequestFactory.setReadTimeout(60 * 1000);
        // 从连接管理器请求连接时使用的超时时间（单位/毫秒），不宜过长，比如连接不够用时，默认值： -1，为无限超时
        clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
        return clientHttpRequestFactory;
    }

    @Bean
    public RestTemplate restTemplate(@Qualifier("clientHttpRequestFactory") ClientHttpRequestFactory clientHttpRequestFactory,
                                     @Qualifier("jacksonObjectMapper") ObjectMapper mapper) {
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
        List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                ((MappingJackson2HttpMessageConverter) converter).setObjectMapper(mapper);
            }
        }
        return restTemplate;
    }
}